package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author liuchun
 * @since 2024-07-02
 */
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {


    private final ILearningLessonService lessonService;

    private final CourseClient courseClient;
    /**
     * 查询学习记录
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //获取当前用户
        Long userId = UserContext.getUser();
        LearningLesson lesson = lessonService.lambdaQuery().eq(LearningLesson::getCourseId, courseId).eq(LearningLesson::getUserId, userId).one();
        if (lesson == null){
            throw new BizIllegalException("课程没有添加至课表!");
        }
        LearningLessonDTO dto = new LearningLessonDTO();
        dto.setId(lesson.getId());
        dto.setLatestSectionId(lesson.getLatestSectionId());
        //这里不用加userId，因为lessonId就是userId和courseId的结合
        List<LearningRecord> recordList = this.lambdaQuery().eq(LearningRecord::getLessonId, lesson.getId()).list();
        List<LearningRecordDTO> list = BeanUtils.copyList(recordList, LearningRecordDTO.class);
        dto.setRecords(list);

        return dto;
    }

    /**
     * 提交学习记录
     * @param dto
     */
    @Override
    @Transactional
    public void commitLearningRecord(LearningRecordFormDTO dto) {
        //获取当前用户
        Long userId = UserContext.getUser();
        //是否是第一次学完
        boolean isFinshed = false;
        //判断提交的记录是课程还是考试
        if (dto.getSectionType().equals(SectionType.VIDEO)) {
            //处理视频
            isFinshed = handleVideoRecord(userId, dto);
        } else {
            //处理考试
            isFinshed = handleExamRecord(userId, dto);
        }
        //处理课表数据
        handleLessonData(dto, isFinshed);
    }
    //处理课表数据
    private void handleLessonData(LearningRecordFormDTO dto, boolean isFinshed) {
        //查询课表
        LearningLesson lesson = lessonService.lambdaQuery().eq(LearningLesson::getId, dto.getLessonId()).one();
        if (lesson == null){
            throw new BizIllegalException("课表信息不存在!");
        }
        //所有小节是否学完
        boolean allFinshed = false;
        //是第一次学完
        if (isFinshed){
            //远程调用课程服务
            CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(dto.getLessonId(), false, false);
            if (cInfo == null){
                throw new BizIllegalException("课程信息不存在!");
            }
            //获取该课程所有的小节数量
            Integer sectionNum = cInfo.getSectionNum();
            Integer learnedSections = lesson.getLearnedSections();
            allFinshed = learnedSections + 1 >= sectionNum;
        }
        boolean success = lessonService.lambdaUpdate()
                .set(allFinshed, LearningLesson::getStatus, LessonStatus.FINISHED)
                .set(lesson.getLearnedSections() == 0, LearningLesson::getStatus, LessonStatus.LEARNING)
                .set(LearningLesson::getLatestSectionId, dto.getSectionId())
                .set(LearningLesson::getLatestLearnTime, dto.getCommitTime())
                .setSql(isFinshed, "learned_sections = learned_sections + 1")
                .eq(LearningLesson::getId, lesson.getId())
                .update();
        if (!success){
            throw new DbException("更新课表数据失败!");
        }

    }
    //处理提交的视频记录
    private boolean handleVideoRecord(Long userId, LearningRecordFormDTO dto) {
        //记录是否存在
        LearningRecord learningRecord = this.lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getLessonId, dto.getLessonId())
                .eq(LearningRecord::getSectionId, dto.getSectionId()).one();
        //为空，新增学习记录
        if (learningRecord == null){
            LearningRecord record = BeanUtils.copyBean(dto, LearningRecord.class);
            record.setUserId(userId);
            boolean success = this.save(record);
            if (!success){
                throw new DbException("新增视频记录失败!");
            }
            return false;
        }
        //判断本小节是否是第一次学完
        boolean isFinshed = !learningRecord.getFinished() && dto.getMoment() * 2 >= dto.getDuration();
        //存在，更新学习记录
        boolean success = this.lambdaUpdate()
                .set(LearningRecord::getMoment, dto.getMoment())
                .set(isFinshed, LearningRecord::getFinished, true)
                .set(isFinshed, LearningRecord::getFinishTime, dto.getCommitTime())
                .eq(LearningRecord::getId, learningRecord.getId())
                .update();
        if (!success){
            throw new DbException("更新视频记录失败!");
        }

        return isFinshed;
    }

    //处理提交的考试记录
    private boolean handleExamRecord(Long userId, LearningRecordFormDTO dto) {
        LearningRecord record = BeanUtils.copyBean(dto, LearningRecord.class);
        record.setUserId(userId);
        record.setFinished(true);
        record.setFinishTime(dto.getCommitTime());
        boolean success = this.save(record);
        if (!success) {
            throw new DbException("新增考试记录失败!");
        }
        return true;
    }


}
